#include "device/air780e/AtNetworkDeviceAir780E.h"

#define GSM_AT_CMD "AT"          // AT测试指令
#define GSM_RESET_CMD "AT+RESET" // 模块重启

#define GSM_CPIN_CMD "AT+CPIN?"     // 检查SIM卡状态
#define GSM_CPIN_RES "+CPIN: READY" // SIM卡状态返回

#define GSM_PREG_CMD "AT+CGREG?"  // 获取PS网络注册状态
#define GSM_PREG_RES "+CGREG: 0," // PS网络注册返回前缀

#define GSM_PDP_CMD "AT+CGPADDR=1" // 获取PDP注册信息(IP地址)
#define GSM_PDP_RES "+CGPADDR: 1," // 获取IP返回前缀

#define GSM_IMEI_CMD "AT+CGSN"  // 获取IMEI
#define GSM_IMEI_RES "\r\n\r\n" // 获取IMEI返回前缀

#define GSM_ICCID_CMD "AT+QCCID" // 获取ICCID
#define GSM_ICCID_RES "+QCCID: " // 获取ICCID返回前缀

#define GSM_RSSI_CMD "AT+CSQ" // 获取信号强度
#define GSM_RSSI_RES "+CSQ: " // 获取信号强度返回前缀

#define GSM_TCP_CFG_TEST "AT+CIFSR" // 查询IP业务激活状态
#define GSM_TCP_CFG_0 "AT+CIPMUX=1" // 开启多路TCP
#define GSM_TCP_CFG_1 "AT+CSTT"     // 设置接入点
#define GSM_TCP_CFG_2 "AT+CIICR"    // 激活移动场景

#define GSM_APN_CFG_TEST "AT+SAPBR=2,1"                   // 查询APN激活状态
#define GSM_APN_CFG_0 "AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"" // 配置APN
#define GSM_APN_CFG_1 "AT+SAPBR=3,1,\"APN\",\"\""         // 配置APN
#define GSM_APN_CFG_2 "AT+SAPBR=1,1"                      // 激活APN

#define GSM_WAIT_TIME() delay(500)

/**
 * 初始化GPRS服务(激活PDP上下文)
 * @param timeout_second 超时时长(秒)
 */
int8_t AtNetworkDeviceAir780E::connect(uint32_t timeout_second) {
  uint32_t expire_time = millis() + timeout_second * 1000;

  // ----------------------------------------------------------
  // - 模块重启
  // ----------------------------------------------------------
  this->streamWriteClear(GSM_RESET_CMD GSM_NL);
  this->streamReleaseInvalidLegacyData();

  // ----------------------------------------------------------
  // - 等待AT指令正常
  // ----------------------------------------------------------
  while (timeout_second > 0 && expire_time > 0) {
    this->streamWriteClear(GSM_AT_CMD GSM_NL);
    if (this->wait(AT_OK) != AT_RCODE1) {
      if (expire_time < millis()) {
        return CONNECT_ERR_1;
      }

      GSM_WAIT_TIME();

      continue;
    }

    break;
  }

  // ----------------------------------------------------------
  // - 等待SIM准备完成
  // ----------------------------------------------------------
  while (timeout_second > 0 && expire_time > 0) {
    this->streamWriteClear(GSM_CPIN_CMD GSM_NL);
    if (this->wait(GSM_CPIN_RES) != AT_RCODE1) {
      if (expire_time < millis()) {
        return CONNECT_ERR_2;
      }

      GSM_WAIT_TIME();

      continue;
    }

    break;
  }

  // ----------------------------------------------------------
  // - 等待PS网络注册完成
  // ----------------------------------------------------------
  while (timeout_second > 0 && expire_time > 0) {
    this->streamWriteClear(GSM_PREG_CMD GSM_NL);
    if (this->wait(GSM_PREG_RES) != AT_RCODE1) {
      if (expire_time < millis()) {
        return CONNECT_ERR_3;
      }

      GSM_WAIT_TIME();

      continue;
    }

    // 获取PS网络注册状态-----------------------
    int ps = this->streamGetInt(1);
    if (ps != 1 && ps != 5) {
      GSM_WAIT_TIME();

      continue;
    }

    break;
  }

  // ----------------------------------------------------------
  // - 获取设备IMEI
  // ----------------------------------------------------------
  this->streamWriteClear(GSM_IMEI_CMD GSM_NL);
  if (this->wait(GSM_IMEI_RES) == AT_RCODE1) {
    this->streamGet(this->imei, 15);
  }

  // ----------------------------------------------------------
  // - 判定联网是否成功&获取IP地址信息
  // ----------------------------------------------------------
  this->streamWriteClear(GSM_PDP_CMD GSM_NL);
  if (this->wait(GSM_PDP_RES) != AT_RCODE1) {
    return CONNECT_ERR_5;
  }

  // 获取IP地址类型(IPV4/IPV6)---------------------
  if (this->streamSkipUntil('\"')) {
    this->streamGet(this->ipv4, 15, '\"');
  }

  if (this->streamSkipUntil('\"')) {
    char *temp = (char *)MEM_ALLOC(64);

    this->streamGet(temp, 63, '\"');

    fmt_ipv6(this->ipv6, temp);

    free(temp);
  }

  // ----------------------------------------------------------
  // - 初始化TCP
  // ----------------------------------------------------------
  this->streamWriteClear(GSM_TCP_CFG_0 GSM_NL);
  if (this->wait(AT_OK) != AT_RCODE1) {
    return CONNECT_ERR_5;
  }

  this->streamWriteClear(GSM_TCP_CFG_1 GSM_NL);
  if (this->wait(AT_OK) != AT_RCODE1) {
    return CONNECT_ERR_5;
  }

  this->streamWriteClear(GSM_TCP_CFG_2 GSM_NL);
  if (this->wait(AT_OK) != AT_RCODE1) {
    return CONNECT_ERR_5;
  }

  this->streamWriteClear(GSM_TCP_CFG_TEST GSM_NL);
  this->streamReleaseInvalidLegacyData();

  // ----------------------------------------------------------
  // - 初始化APN
  // ----------------------------------------------------------
  this->streamWriteClear(GSM_APN_CFG_0 GSM_NL);
  if (this->wait(AT_OK) != AT_RCODE1) {
    return CONNECT_ERR_5;
  }

  this->streamWriteClear(GSM_APN_CFG_1 GSM_NL);
  if (this->wait(AT_OK) != AT_RCODE1) {
    return CONNECT_ERR_5;
  }

  this->streamWriteClear(GSM_APN_CFG_2 GSM_NL);
  if (this->wait(AT_OK) != AT_RCODE1) {
    return CONNECT_ERR_5;
  }

  this->streamWriteClear(GSM_APN_CFG_TEST GSM_NL);
  this->streamReleaseInvalidLegacyData();

  return true;
}

/**
 * 获取设备固件版本
 */
String AtNetworkDeviceAir780E::getDeviceVersion(uint32_t timeout) {
  this->streamWriteClear("AT+CGMR" GSM_NL);

  if (this->wait("+CGMR: \"") == AT_RCODE1) {
    char result[32] = {0};

    this->streamGet(result, 32, '\"');

    return String(result);
  }

  return String("ERROR");
}

/**
 * 获取设备型号
 */
String AtNetworkDeviceAir780E::getDeviceModel(uint32_t timeout) {
  this->streamWriteClear("AT+CGMM" GSM_NL);

  if (this->wait("+CGMM: \"") == AT_RCODE1) {
    char result[16] = {0};

    this->streamGet(result, 16, '\"');

    return String(result);
  }

  return String("ERROR");
}

/**
 * 获取设备IMEI
 */
String AtNetworkDeviceAir780E::getDeviceIMEI(uint32_t timeout) {
  this->streamWriteClear("AT+CGSN" GSM_NL);

  if (this->wait("+CGSN\r\r\n") == AT_RCODE1) {
    char result[16] = {0};

    this->streamGet(result, 16, '\r');

    return String(result);
  }

  return String("ERROR");
}

/**
 * 获取设备ICCID
 */
String AtNetworkDeviceAir780E::getIccid(uint32_t timeout) {
  this->streamWriteClear("AT+ICCID" GSM_NL);

  if (this->wait("+ICCID: ") == AT_RCODE1) {
    char result[24] = {0};

    this->streamGet(result, 24, '\r');

    return String(result);
  }

  return String("ERROR");
}

/**
 * 获取设备RSSI(信号强度)
 */
int AtNetworkDeviceAir780E::getRssi(uint32_t timeout) {
  this->streamWriteClear("AT+CSQ" GSM_NL);

  if (this->wait("+CSQ: ") == AT_RCODE1) {
    return this->streamGetInt(4, ',');
  }

  return 0;
}
